using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Windows.Forms;

namespace minega
{
	public class Server
	{
		Socket _mainSocket;
		List<Socket> _clients = new List<Socket>();
		AsyncCallback _clientCallback = null;

		/// <summary>
		/// Gets the ip of the server
		/// </summary>
		public string IP
		{
			get
			{
				string strHostName = Dns.GetHostName();
				IPHostEntry ipHostEntry = Dns.GetHostEntry(strHostName);
				foreach (IPAddress ipAddress in ipHostEntry.AddressList)
				{
					return ipAddress.ToString();
				}
				return "";
			}
		}

		public Server()
		{

		}

		public void StartListen()
		{
			try
			{
				_mainSocket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
				IPEndPoint local = new IPEndPoint(IPAddress.Any, 1234);
				_mainSocket.Bind(local);
				_mainSocket.Listen(4);
				_mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);
			}
			catch (SocketException se)
			{
				MessageBox.Show(se.Message);
			}
		}

		public void StopListen()
		{
			// Close all sockets
			if (_mainSocket != null)
				_mainSocket.Close();
			for (int i = 0; i < _clients.Count; i++)
			{
				if (_clients[i] != null)
					_clients[i].Close();
			}
			_clients.Clear();
		}

		public void OnClientConnect(IAsyncResult async)
		{
			try
			{
				Socket client = _mainSocket.EndAccept(async);
				_clients.Add(client);

				WaitForData(client);
				_mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);
			}
			catch (SocketException se)
			{
				MessageBox.Show(se.Message);
			}
		}

		private void WaitForData(Socket client)
		{
			try
			{
				if (_clientCallback == null)
				{
					_clientCallback = new AsyncCallback(OnDataReceived);
				}
				SocketPack sp = new SocketPack(client);
				client.BeginReceive(
					sp._buffer,
					0,
					sp._buffer.Length,
					SocketFlags.None,
					_clientCallback,
					sp
				);
			}
			catch (SocketException se)
			{
				MessageBox.Show(se.Message);
			}
		}

		private void OnDataReceived(IAsyncResult async)
		{
			SocketPack sp = (SocketPack)async.AsyncState;
			try
			{
				int recieved = sp.Socket.EndReceive(async);
				// Do something with the shit received in sp._buffer
				WaitForData(sp.Socket);
			}
			catch (SocketException se)
			{
				if (se.ErrorCode == 10054)	// Client not connected
				{
					_clients.Remove(sp.Socket);
				}
				else
				{
					MessageBox.Show(se.Message);
				}
			}
		}

		public void SendData(byte[] buffer, Socket client)
		{
			try
			{
				if (client != null)
				{
					if (client.Connected)
					{
						client.Send(buffer);
					}
				}
			}
			catch (SocketException se)
			{
				MessageBox.Show(se.Message);
			}
		}
	}
}
